package com.test.manage.building;

import com.test.manage.building.bean.Building;
import com.test.manage.building.bean.BuildingConstants;
import com.test.manage.building.bean.BuildingDTO;
import com.test.manage.building.bean.BuildingPhoto;
import com.test.uilt.Arith;
import com.test.uilt.DateUtil;
import com.test.uilt.PhotoUtils;
import com.test.uilt.excel.ExcelExportUtil;
import com.test.uilt.excel.ExportExcel;
import com.test.uilt.excel.PojoImportField;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class BuildingUtils {

    /**
     * 当前日期
     */
    public static String DATE_TIME = DateUtil.getCurrentTime();

    /**
     * 用于启用多线程时 控制台输出记录楼栋总数量
     */
    public static int buildingSize = 0;

    /**
     * 用于启用多线程时 控制台输出已完成的数量
     */
    public static int buildingCount = 0;


    /**
     * 生成图片ID
     */
    public static Long ID = 78368L;

    /**
     * 获取楼栋的ids
     * @param excel
     * @param sheetNum
     * @return
     */
    public static List<Building> importExcel(File excel, int sheetNum) {
        int rowNum = 1;//导入数据的第几行
        HSSFWorkbook book = null;
        try {
            book = ExcelExportUtil.getWorkBook(excel);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 获得第几页sheet
        HSSFSheet sheet = book.getSheetAt(sheetNum);

        //获取excel的所有id
        List<Building> ids = new ArrayList<>();

        if (sheet.getPhysicalNumberOfRows() > 1) {
            try {
                // 得到第一页的所有行
                Iterator<Row> row = sheet.rowIterator();

                //标题所在的行数
                int getRowNum = 1;
                Row title = null;
                for (int i = 0; i < getRowNum; i++) {
                    title = row.next();
                }
                // 得到第一行的所有列，根据bean的@excel注解找到对应的id列
                PojoImportField pif = ExcelExportUtil.getFieldMap(Building.class);
                Map<Integer, String> titlemap = ExcelExportUtil.getExcelTitleMap(title);
                while (row.hasNext()) {
                    Building view = (Building) ExcelExportUtil.getImportExcelObject(row, titlemap, pif, Building.class);
                    if (view.getId() != null && view.getId() != "") {
                        //添加数据
                        ids.add(view);
                    } else {
                        throw new Exception("第" + rowNum+ "行“id”列不能为空或请检查表头！");
                    }

                    rowNum++;
                }
            } catch (Exception e) {
                e.printStackTrace();
                try {
                    throw new Exception("第" + rowNum+ "行“id”列不能为空或请检查表头！");
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
        return ids;
    }

    /**
     * 设置插入图片表的sql
     * @param buildingPhotoList
     * @param dowload
     */
    public static void setBuildingPhotoSqlExcel(List<BuildingPhoto> buildingPhotoList, String dowload) {
        FileOutputStream output = null;
        try {
            //根据bean 注解的@excel 生成excel
            HSSFWorkbook workbook = new ExportExcel<BuildingPhoto>().exportExcel("sheet1", BuildingPhoto.class, buildingPhotoList, new ArrayList<String>());

            //判断是否存在目录. 不存在则创建
            PhotoUtils.isChartPathExist(dowload);
            //输出Excel文件
            output = new FileOutputStream(dowload);
            //写入磁盘
            workbook.write(output);
            output.close();

        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != output) {
                    output.close();
                }
            } catch (IOException e) {

            }
        }
    }

    /**
     * 根据别墅id设置别墅图片
     * @param infos
     * @param dto
     */
    public static void setBuildingPhotoList(List<Building> infos, BuildingDTO dto) {
        /**
         * 用于启用多线程时 多个线程同时设置楼栋图像信息
         */
        List<BuildingPhoto> buildingPhotoList = new ArrayList<>();

        buildingSize = infos.size();
        System.out.println(DateUtil.getCurrentTime());
        /**
         * 经测试，copy缓存调大效果与多开线程差不多，主要是磁盘io吞吐限制。
         * 多线程还要考虑时间按照顺序增加
         */
//        setSyncBuildingPhotoAdd(buildingPhotoList, infos);

        //单线程循环
        for (Building info : infos) {
            //设置楼栋图像表的sql信息插入语句，以及导入服务器的图片
            buildingPhotoList.addAll(setBuildingPhotoAdd(info, dto));
        }


        //导出插入楼栋图片表的sql excel文件
        setBuildingPhotoSqlExcel(buildingPhotoList, dto.getExcelDowloadPath());

        System.out.println(DateUtil.getCurrentTime());
        System.out.println("请将 [ " + dto.getExcelDowloadPath() + " ] 打开，根据数据库 [ building_photo ] 表中最大id + 1手动设置到excel，并执行。");
        System.out.println("请将 [ " + dto.getDowloadPath() + " ] 文件夹下的所有图片复制到服务器 [building/ ] 文件夹下。");

    }

    /**
     * 开启多线程
     * @param infos
     */
    public static List<BuildingPhoto> setSyncBuildingPhotoAdd(List<BuildingPhoto> buildingPhotoList, List<Building> infos, BuildingDTO dto) {
        int buildingCount = infos.size();
        //线程开多了，容易down机
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        List<Future<Integer>> futureList =new ArrayList<Future<Integer>>(buildingCount);
        for(final Building info : infos){
            //也可以使用实现Runnable的方法
            Callable<Integer> runnale = new Callable<Integer>() {
                @Override
                public  Integer call() {
                    //处理业务
                    try {
                        buildingPhotoList.addAll(setBuildingPhotoAdd(info, dto));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return 0;//无用返回
                }
            };
            Future<Integer> future = executorService.submit(runnale);
            futureList.add(future);
        }
        //主线程阻塞，等待子线程执行完毕并返回结果
        PhotoUtils.syncFuture(futureList);


        //关闭线程池
        executorService.shutdown();

        return buildingPhotoList;
    }

    /**
     * 设置楼栋图片插入语句以及生成图片
     * @param dto
     * @return
     */
    public static List<BuildingPhoto> setBuildingPhotoAdd(Building info, BuildingDTO dto) {
        //获取随机一张图片，作为当前楼栋的六个影响
        File file = PhotoUtils.getRandomSelection(dto.getFiles());
        //设置sql导出的bean
        List<BuildingPhoto> list = new ArrayList<BuildingPhoto>();

        //图片名称
        dto.setConstants(BuildingConstants.BUILDING_BRAND_TYPE);
        setBuildingPhoto(list, file, info, dto);

        dto.setConstants(BuildingConstants.BUILDING_WHOLE_TYPE);
        setBuildingPhoto(list, file, info, dto);

        dto.setConstants(BuildingConstants.BUILDING_UNIT_GATE_TYPE);
        setBuildingPhoto(list, file, info, dto);

        dto.setConstants(BuildingConstants.BUILDING_LAYER_TYPE);
        setBuildingPhoto(list, file, info, dto);

        dto.setConstants(BuildingConstants.BUILDING_FIRST_FLOOR_NUMBER_TYPE);
        setBuildingPhoto(list, file, info, dto);

        dto.setConstants(BuildingConstants.BUILDING_TOP_FLOOR_NUMBER_TYPE);
        setBuildingPhoto(list, file, info, dto);

        System.out.println("共" + buildingSize + "栋楼，已生成第" + ++buildingCount + "栋， 已完成 [ " + Arith.round(Double.valueOf(buildingCount)/Double.valueOf(buildingSize) *100, 0) + "% ]");
        return list;
    }


    public static void setBuildingPhoto(List<BuildingPhoto> list, File file, Building info, BuildingDTO dto) {

        //设置图片结尾 例如.jpg
        String[] split = file.getName().split("\\.");
        String photoType = "." + split[split.length - 1];
        String pathPhotoName = getUuid() + photoType;

        //sql的开头 building_photo
        String sqlStar = "INSERT INTO building_photo (id, photo_name, photo_path, create_date, remarks, building_id, type, creater) VALUES (";

        int size = 0;
        if (BuildingConstants.BUILDING_VILLAGE_TYPE[1].equals(dto.getBuildingYype())) {

            //根据单元数量生成对应的图片数量

            //如果单元为NULL生成两张图片
            if (!"NULL".equals(info.getUnitQuantity())) {
                size = Integer.valueOf(info.getUnitQuantity());
            } else {
                size = 2;
            }
        } else if (BuildingConstants.BUILDING_VILLA_TYPE[1].equals(dto.getBuildingYype())){
            //别墅循环一次
            size = 1;

            //拷贝随机的图片设置uuid
            PhotoUtils.copyPhotoToDest(file, dto.getDowloadPath(), pathPhotoName);
        }

        for (int i = 0; i < size; i++) {
            //数据库排序按照时间所以时间秒数+1
            list.add(new BuildingPhoto(sqlStar, ID++ +",", "\"" + dto.getConstants()[0] + "\",", "\"building/" + pathPhotoName + "\",", DATE_TIME = PhotoUtils.getBuildingPhotoDATE_TIME(DATE_TIME), "NULL,", info.getId() + ",", dto.getConstants()[1] + ",", "NULL", ");"));

            if (BuildingConstants.BUILDING_BRAND_TYPE[1].equals(dto.getConstants()[1])
                    || BuildingConstants.BUILDING_WHOLE_TYPE[1].equals(dto.getConstants()[1])) {
                break;
            }
            //重置绑定uuid
            pathPhotoName = getUuid() + photoType;
        }
    }

    public static String getUuid() {
       return UUID.randomUUID().toString();
    }
}
